package com.leil.movies.project.rest.handler;

import com.leil.movies.project.rest.constant.DouBanHttpStatusCode;
import com.leil.movies.project.rest.exception.DouBanApiException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.lang.Nullable;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.client.ResponseErrorHandler;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URI;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

public class DouBanApiErrorHandler implements ResponseErrorHandler {

    private final Logger logger = LoggerFactory.getLogger(DouBanApiErrorHandler.class);

    @Override
    public boolean hasError(ClientHttpResponse clientHttpResponse) throws IOException {
        return clientHttpResponse.getStatusCode().value() != DouBanHttpStatusCode.OK.getCode()
                && clientHttpResponse.getStatusCode().value() != DouBanHttpStatusCode.CREATED.getCode()
                && clientHttpResponse.getStatusCode().value() != DouBanHttpStatusCode.ACCEPTED.getCode();
    }

    @Override
    public void handleError(ClientHttpResponse clientHttpResponse) throws IOException {

    }

    @Override
    public void handleError(URI url, HttpMethod method, ClientHttpResponse response) throws IOException {
        String message = this.getErrorMessage(
                response.getRawStatusCode(),
                response.getStatusText(),
                this.getResponseBody(response),
                this.getCharset(response));
        logger.error(message);
        throw new DouBanApiException(message);
    }

    private String getErrorMessage(int rawStatusCode, String statusText, @Nullable byte[] responseBody, @Nullable Charset charset) {
        String preface = rawStatusCode + " " + statusText + ": ";
        if (ObjectUtils.isEmpty(responseBody)) {
            return preface + "[no body]";
        } else {
            charset = charset == null ? StandardCharsets.UTF_8 : charset;
            int maxChars = 200;
            if (responseBody.length < maxChars * 2) {
                return preface + "[" + new String(responseBody, charset) + "]";
            } else {
                try {
                    Reader reader = new InputStreamReader(new ByteArrayInputStream(responseBody), charset);
                    CharBuffer buffer = CharBuffer.allocate(maxChars);
                    reader.read(buffer);
                    reader.close();
                    buffer.flip();
                    return preface + "[" + buffer.toString() + "... (" + responseBody.length + " bytes)]";
                } catch (IOException var9) {
                    throw new IllegalStateException(var9);
                }
            }
        }
    }

    protected byte[] getResponseBody(ClientHttpResponse response) {
        try {
            return FileCopyUtils.copyToByteArray(response.getBody());
        } catch (IOException var3) {
            return new byte[0];
        }
    }

    @Nullable
    protected Charset getCharset(ClientHttpResponse response) {
        HttpHeaders headers = response.getHeaders();
        MediaType contentType = headers.getContentType();
        return contentType != null ? contentType.getCharset() : null;
    }
}
